package gpeerreview.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Grid;

class KeyPair
{
	public BigInt m_public;
	public BigInt m_private;
	public BigInt m_n;
	private int m_blockSize;

	public KeyPair()
	{
	}

	public KeyPair(String s)
	{
		int first = s.indexOf(",");
		int second = -1;
		if(first >= 0)
		{
			second = s.indexOf(",", first + 1);
			m_n = new BigInt(s.substring(0, first));
			if(second >= 0)
			{
				m_public = new BigInt(s.substring(first + 1, second));
				m_private = new BigInt(s.substring(second + 1));
			}
			else
				m_public = new BigInt(s.substring(first + 1));
		}
		else
			m_n = new BigInt(s);
	}

	public String publicToString()
	{
		return m_n.toString() + "," + m_public.toString();
	}

	public String privateToString()
	{
		return publicToString() + "," + m_private.toString();
	}

	public int GetCypherBlockSize()
	{
		if(m_blockSize == 0)
		{
			byte[] arr = m_n.toByteArray();
			m_blockSize = arr.length;
		}
		return m_blockSize;
	}

	public int GetTextBlockSize()
	{
		return GetCypherBlockSize() - 1;
	}

	private byte[] ApplyKey(byte[] block, BigInt key, int sizeIn, int sizeOut)
	{
		if(block.length != sizeIn)
			throw new IllegalArgumentException("wrong block size");
		BigInt input = new BigInt(block);
		BigInt output = input.modPow(key, m_n);
		byte[] results = output.toByteArray();

		// Ensure correct block size
		if(results.length != sizeOut)
		{
			if(results.length > sizeOut)
			{
				Window.alert("invalid cypher or key");
				throw new IllegalArgumentException("invalid cypher or key");
			}
			byte[] copy = new byte[sizeOut];
			int i;
			for(i = 0; i < results.length; i++)
				copy[i] = results[i];
			for( ; i < copy.length; i++)
				copy[i] = 0;
			results = copy;
		}
		return results;
	}

	public byte[] Sign(byte[] block)
	{
		return ApplyKey(block, m_private, GetTextBlockSize(), GetCypherBlockSize());
	}

	public byte[] Authenticate(byte[] block)
	{
		return ApplyKey(block, m_public, GetCypherBlockSize(), GetTextBlockSize());
	}

	public byte[] Encrypt(byte[] block)
	{
		return ApplyKey(block, m_public, GetTextBlockSize(), GetCypherBlockSize());
	}

	public byte[] Decrypt(byte[] block)
	{
		return ApplyKey(block, m_private, GetCypherBlockSize(), GetTextBlockSize());
	}
}
